package cn.keniykey.mc.landterritory.landview;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;

import cn.keniykey.mc.generallibrary.input.api.EInputResult;
import cn.keniykey.mc.landterritory.config.ConfigurationManager;
import cn.keniykey.mc.landterritory.config.LanguageManager;
import cn.keniykey.mc.landterritory.config.WorldsConfiguration;
import cn.keniykey.mc.landterritory.event.LandUpdateDataEvent;
import cn.keniykey.mc.landterritory.land.LandManager;
import cn.keniykey.mc.landterritory.land.api.ELandType;
import cn.keniykey.mc.landterritory.land.api.Land;
import cn.keniykey.mc.landterritory.land.api.LandPoint;
import cn.keniykey.mc.landterritory.land.api.LandPosition;
import cn.keniykey.mc.landterritory.land.api.LandRange;
import cn.keniykey.mc.landterritory.land.api.LandUtil;
import cn.keniykey.mc.landterritory.land.api.LandUtil.ELandPermissionLevel;
import cn.keniykey.mc.landterritory.landflag.LandFlag;
import cn.keniykey.mc.landterritory.landflag.api.LandFlagSetting;
import cn.keniykey.mc.landterritory.toolkit.Util;
import cn.keniykey.mc.landterritory.vault.Perm;

public final class LandViewUtil {
	private LandViewUtil() {
		throw new RuntimeException("NULL");
	}
	
	public static final String INPUT_COMMAND_STR = "s";
	private static final String RANGE_NULL_STR = "?";
	private static final int ENTER_LEAVE_STR_LINE_LENGTH = 30;
	private static Method Method_World_GetMin;
	
	static {
		try {
			Method_World_GetMin = World.class.getMethod("getMinHeight");
			Method_World_GetMin.setAccessible(true);
		}catch(Exception ex) {}
	}
	
	public static String getLandLabelStr(Land land) {
		return LanguageManager.getLang(1004000, LanguageManager.getLang(land.getType().getLang()), land.getID(), land.getName());
	}
	public static String getFaceStr(BlockFace face) {
		final int lang;
		switch(face) {
		case UP:
			lang = 1006500;
			break;
		case DOWN:
			lang = 1006501;
			break;
		case EAST:
			lang = 1006502;
			break;
		case SOUTH:
			lang = 1006503;
			break;
		case WEST:
			lang = 1006504;
			break;
		case NORTH:
			lang = 1006505;
			break;
		default:
			return face.toString();
		}
		return LanguageManager.getLang(lang, false);
	}
	static int getLandFlagParAmount(Land land,LandFlag landflag) {
		final String flagname = landflag.getName();
		if(!land.getFlags().containsKey(flagname)) return 0;
		final Set<String> pars = land.getFlags().get(flagname);
		return pars.size();
	}
	static int getLandFlagParMaxAmount(LandFlag landflag) {
		switch(landflag.getELandFlagParType()) {
		case MUCH:
			return ConfigurationManager.View_FlagInfo_ParameterLimit;
		case ONLY:
			return 1;
		default:
		}
		return 0;
	}
	static ELandPermissionLevel getLandFLagMinPermissionLevel(LandFlag landflag) {
		ELandPermissionLevel level = ELandPermissionLevel.FLAG_FLAGADMIN;
		final String flagname = landflag.getName();
		if(LandFlagSetting.getLandAuthority(flagname) != null) {
			level = ELandPermissionLevel.OWNER;
		}else if(LandFlagSetting.getFlagAuthority(flagname) != null) level = ELandPermissionLevel.FLAG_LANDADMIN;
		return level;
	}
	public static String getLandRangeListStr(LandRange range) {
		final LandPoint point1 = range.getLandPointOne(),point2 = range.getLandPointTwo();
		String x1 = RANGE_NULL_STR,y1 = RANGE_NULL_STR,z1 = RANGE_NULL_STR;
		String x2 = RANGE_NULL_STR,y2 = RANGE_NULL_STR,z2 = RANGE_NULL_STR;
		if(point1 != null) {
			x1 = String.valueOf(point1.getX());
			y1 = String.valueOf(point1.getY());
			z1 = String.valueOf(point1.getZ());
		}
		if(point2 != null) {
			x2 = String.valueOf(point2.getX());
			y2 = String.valueOf(point2.getY());
			z2 = String.valueOf(point2.getZ());
		}
		final String worldname = (range.getWorldName() == null ? RANGE_NULL_STR : range.getWorldName());
		return LanguageManager.getLang(1006001, WorldsConfiguration.getWorldName(worldname), worldname,
				x1,y1,z1,x2,y2,z2);
	}
	static void checkSendLandPosInRange(Player player,Land land) {
		if(land.getRange().isInRange(land.getPos())) return;
		final Location loc_player = player.getLocation();
		if(land.getRange().isInRange(loc_player)) {
			land.setPos(new LandPosition(loc_player));
			player.sendMessage(LanguageManager.getChatLang(1006124));
		}else {
			final LandPosition pos = land.getPos();
			final LandPoint point = land.getRange().getCenterPoint();
			land.setPos(new LandPosition(point.getWorldName(), point.getX()+0.5d, point.getY()+0.1d, point.getZ()+0.5d,
					pos.getYaw(), pos.getPitch()));
			player.sendMessage(LanguageManager.getChatLang(1006125));
		}
		Bukkit.getPluginManager().callEvent(new LandUpdateDataEvent(player, land));
	}
	public static List<String> getLandInfoItemStack(Land land) {
		final StringBuilder builder = new StringBuilder();
		//领地基本信息
		final String owner_name;
		if(land.isSystem()) {
			owner_name = LanguageManager.getPrefix();
		}else {
			final Player owner = Bukkit.getPlayer(land.getOwner());
			if(owner == null) {
				final OfflinePlayer offplayer = Bukkit.getOfflinePlayer(land.getOwner());
				owner_name = (offplayer.hasPlayedBefore() ? offplayer.getName() : LanguageManager.getLang(1107110));
			}else {
				owner_name = owner.getName();
			}
		}
		builder.append(LanguageManager.getLang(1107000, LanguageManager.getLang(land.getType().getLang()), land.getLevel(),
				owner_name, LanguageManager.getLang((land.isOverLap() ? 1107100 : 1107101))));
		//领地范围信息
		builder.append("\n");
		final LandPosition pos = land.getPos();
		final LandPoint point1 = land.getRange().getLandPointOne();
		final LandPoint point2 = land.getRange().getLandPointTwo();
		builder.append(LanguageManager.getLang(1107001, WorldsConfiguration.getWorldName(point1.getWorldName()),
				point1.getX(), point1.getY(), point1.getZ(), point2.getX(), point2.getY(), point2.getZ(),
				pos.getX(), pos.getY(), pos.getZ()));
		//领地销售信息
		if(land.getPrice() >= 0) {
			builder.append("\n").append(LanguageManager.getLang(1106000, land.getPrice()));
		}
		//领地进入消息
		if(land.getEnterMessage() != null && !land.getEnterMessage().isEmpty()) {
			builder.append("\n").append(LanguageManager.getLang(1107002)).append("\n");
			builder.append(Util.strSubToLine(Util.conver(land.getEnterMessage()),ENTER_LEAVE_STR_LINE_LENGTH, "§r "));
		}
		//领地离开消息
		if(land.getLeaveMessage() != null && !land.getLeaveMessage().isEmpty()) {
			builder.append("\n").append(LanguageManager.getLang(1107003)).append("\n");
			builder.append(Util.strSubToLine(Util.conver(land.getLeaveMessage()),ENTER_LEAVE_STR_LINE_LENGTH, "§r "));
		}
		return Util.listFromStr(builder.toString());
	}
	static boolean hasSendUsePermission(Player player,String worldname,@Nullable String per,int lang) {
		if(per == null || per.isEmpty()) return true;
		if(Perm.getPerm().hasPermission(worldname, player, per)) return true;
		player.sendMessage(LanguageManager.getChatLang(1005001, LanguageManager.getLang(lang)));
		return false;
	}
	static boolean hasSendLandPermission(Player player,Land land,ELandPermissionLevel minlevel,int lang) {
		if(LandUtil.hasLandPermission(player, land, minlevel)) return true;
		player.sendMessage(LanguageManager.getChatLang(1005000, LanguageManager.getLang(lang)));
		return false;
	}
	static boolean isRangeAccordWithLand(LandRange range,ELandType type,@Nullable Player player) {
		final Set<String> set_range_worlds;
		final List<Long> list_range_size;
		final List<Integer> list_range_xyz;
		final String per;
		switch(type) {
		case TERRITORY:
			set_range_worlds = ConfigurationManager.Territory_Limit_Worlds;
			list_range_size = ConfigurationManager.Territory_Limit_Size;
			list_range_xyz = ConfigurationManager.Territory_Limit_XYZ;
			per = ConfigurationManager.Territory_Limit_Per;
			break;
		case COMMUNITY:
			set_range_worlds = ConfigurationManager.Community_Limit_Worlds;
			list_range_size = ConfigurationManager.Community_Limit_Size;
			list_range_xyz = ConfigurationManager.Community_Limit_XYZ;
			per = ConfigurationManager.Community_Limit_Per;
			break;
		case GROUND:
			set_range_worlds = ConfigurationManager.Community_Limit_Worlds;
			list_range_size = Collections.emptyList();
			list_range_xyz = Collections.emptyList();
			per = ConfigurationManager.Community_Limit_Per;
			break;
		default:
			return false;
		}
		if(player != null && Perm.getPerm().hasPermission(range.getWorldName(), player, per)) return true;
		if(!set_range_worlds.contains(range.getWorldName())) {
			if(player != null) player.sendMessage(LanguageManager.getChatLang(1006112, LanguageManager.getLang(type.getLang())));
			return false;
		}
		if(list_range_size.isEmpty() && list_range_xyz.isEmpty()) return true;
		long size = (list_range_size.size() >= 1 ? list_range_size.get(0) : 0l);
		int x = (list_range_xyz.size() >= 1 ? list_range_xyz.get(0) : 0);
		int y = (list_range_xyz.size() >= 2 ? list_range_xyz.get(1) : 0);
		int z = (list_range_xyz.size() >= 3 ? list_range_xyz.get(2) : 0);
		long sizel = range.getSize();
		int xl = range.getXLength();
		int yl = range.getYLength();
		int zl = range.getZLength();
		if((size > 0l && sizel > size) || (x > 0 && xl > x) || (y > 0 && yl > y) || (z > 0 && zl > z)) {
			if(player != null) player.sendMessage(LanguageManager.getChatLang(1006110, LanguageManager.getLang(type.getLang()), size, x, y, z));
			return false;
		}
		size = (list_range_size.size() >= 2 ? list_range_size.get(1) : 0l);
		x = (list_range_xyz.size() >= 4 ? list_range_xyz.get(3) : 0);
		y = (list_range_xyz.size() >= 5 ? list_range_xyz.get(4) : 0);
		z = (list_range_xyz.size() >= 6 ? list_range_xyz.get(5) : 0);
		if((size > 0l && sizel < size) || (x > 0 && xl < x) || (y > 0 && yl < y) || (z > 0 && zl < z)) {
			if(player != null) player.sendMessage(LanguageManager.getChatLang(1006111, LanguageManager.getLang(type.getLang()), size, x, y, z));
			return false;
		}
		return true;
	}
	static boolean isHighlyAccordWithWorld(LandRange range,World world,@Nullable Player player) {
		final int max = world.getMaxHeight();
		final int min = getWorldMinHighly(world);
		final int highly_p1 = range.getLandPointOne().getY();
		final int highly_p2 = range.getLandPointTwo().getY();
		if(highly_p1 >= min && highly_p1 <= max && highly_p2 >= min && highly_p2 <= max) return true;
		if(player != null) player.sendMessage(LanguageManager.getChatLang(1006113, max , min));
		return false;
	}
	static int getWorldMinHighly(World world) {
		try {
			return (Method_World_GetMin != null ? (int)Method_World_GetMin.invoke(world) : 0);
		}catch(Exception ex) {
			Method_World_GetMin = null;
			return 0;
		}
	}
	static boolean checkRangeCollision(final Player player,final ELandType type,final LandRange range) {
		switch(type) {
		case TERRITORY:
			LinkedList<Land> linke_collision_lands = LandManager.getLandManager().getCollisionLands(range);
			try {
				for(final Land cland : linke_collision_lands) {
					if(!cland.isOverLap()) {
						sendLandOverLap(player, null, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			break;
		case COMMUNITY:
			linke_collision_lands = LandManager.getLandManager().getCollisionLands(range);
			try {
				for(final Land cland : linke_collision_lands) {
					if(!cland.isOverLap() && !ELandType.GROUND.equals(type)) {
						sendLandOverLap(player, null, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			break;
		case GROUND:
			Land land_community = null;
			linke_collision_lands = LandManager.getLandManager().getCollisionLands(range);
			try {
				for(final Land cland : linke_collision_lands) {
					if(ELandType.COMMUNITY.equals(cland.getType()) && cland.equalsOwner(player) && 
							range.isInRange(cland.getRange())) {
						land_community = cland;
					}
					if(!ELandType.COMMUNITY.equals(cland.getType()) && !cland.isOverLap()) {
						sendLandOverLap(player, null, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			if(land_community == null) {
				player.sendMessage(LanguageManager.getChatLang(1006122));
				return false;
			}
			break;
		default:
		}
		return true;
	}
	static boolean checkRangeExpandCollision(Player player,Land land,final LandRange range_new) {
		switch(land.getType()) {
		case TERRITORY:
			if(land.isOverLap()) break;
			LinkedList<Land> linke_collision_lands = LandManager.getLandManager().getCollisionLands(range_new);
			try {
				for(final Land cland : linke_collision_lands) {
					if(!cland.isOverLap() && !cland.equals(land)) {
						sendLandOverLap(player, land, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			break;
		case COMMUNITY:
			linke_collision_lands = LandManager.getLandManager().getCollisionLands(range_new);
			try {
				for(final Land cland : linke_collision_lands) {
					if(!cland.isOverLap() && !ELandType.GROUND.equals(land.getType()) && !cland.equals(land)) {
						sendLandOverLap(player, land, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			break;
		case GROUND:
			Land land_community = null;
			linke_collision_lands = LandManager.getLandManager().getCollisionLands(range_new);
			try {
				for(final Land cland : linke_collision_lands) {
					if(ELandType.COMMUNITY.equals(cland.getType()) && cland.equalsOwner(land) && 
							land.getRange().cover(cland.getRange()) && range_new.isInRange(cland.getRange())) {
						land_community = cland;
					}
					if(!ELandType.COMMUNITY.equals(cland.getType()) && !cland.isOverLap() && !cland.equals(land)) {
						sendLandOverLap(player, land, cland);
						return false;
					}
				}
			}finally {
				linke_collision_lands.clear();
			}
			if(land_community == null) {
				player.sendMessage(LanguageManager.getChatLang(1006122));
				return false;
			}
			break;
		default:
		}
		return true;
	}
	static boolean checkRangeReduceCollision(Player player,Land land,final LandRange range_new) {
		switch(land.getType()) {
		case COMMUNITY:
			for(final Land cland : LandManager.getLandManager().getServerLands(ELandType.GROUND)) {
				if(land.getRange().cover(cland.getRange()) && !cland.getRange().isInRange(range_new)) {
					player.sendMessage(LanguageManager.getChatLang(1006122));
					return false;
				}
			}
			break;
		default:
		}
		return true;
	}
	static void sendLandOverLap(Player player,@Nullable Land land, Land cland) {
		if(land == null) {
			player.sendMessage(LanguageManager.getChatLang(1006120, getLandLabelStr(cland)));
			return;
		}
		player.sendMessage(LanguageManager.getChatLang(1006121, getLandLabelStr(land), getLandLabelStr(cland)));
	}
	public static void inputResultResponse(EInputResult result, OfflinePlayer offplayer, boolean cancel, int lang) {
		if(EInputResult.INPUT.equals(result)) {
			if(!cancel) ((Player)offplayer).sendMessage(LanguageManager.getChatLang(1007002));
			return;
		}
		final Player player = offplayer.getPlayer();
		if(player != null) player.sendMessage(LanguageManager.getChatLang(1007001, LanguageManager.getLang(lang)));
	}
	static void sendInputNotInconformity(Player player,int lang) {
		player.sendMessage(LanguageManager.getChatLang(1007000, LanguageManager.getLang(lang)));
	}
	static void sendInputNotFoundPlayer(Player player,String str) {
		player.sendMessage(LanguageManager.getChatLang(1007003, str));
	}
	static void sendInputStrLength(Player player,int min,int max) {
		player.sendMessage(LanguageManager.getChatLang(1007004, min, max));
	}
	static void sendInputMustNotNegativeNumber(Player player) {
		player.sendMessage(LanguageManager.getChatLang(1007005));
	}
	static void sendInputMustPositiveNumber(Player player) {
		player.sendMessage(LanguageManager.getChatLang(1007007));
	}
	static void sendInputNotOnlyNumber(Player player) {
		player.sendMessage(LanguageManager.getChatLang(1007006));
	}
}